﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace IAP
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        string filename = @"C:\Users\yg.hu\Desktop\emwin.bin";
        bool ReceivedOk = false;    //与硬件建立连接标志
        byte[][] FileReadByte = new byte[300][];   //读取bin文件缓冲
        bool SendFlag = false;
        Thread t;
        int ByteOne;        //分段发送的大小 ByteOne = 50K
        FileStream FileNameStr;
        int timerCount = 0;
        Thread tTime;

        private void bchoosefile_Click(object sender, EventArgs e)
        {
            try
            {
                openfile.ShowDialog();//文件读取窗口
                filename = openfile.FileName;//获取文件名
                tbfilename.Text = filename;
                FileNameStr = File.OpenRead(filename);
                long FileLen = FileNameStr.Length;
                textBox1.Text = (FileLen / 1024).ToString() + "K";
                
            }
            catch (Exception Err)               
            {
                MessageBox.Show(Err.Message);
            }
            FileNameStr.Close();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            filename = Properties.Settings.Default.filename;
            tbfilename.Text = filename;
            comboBox2.Text = Properties.Settings.Default.BaudRate;
            comboBox1.Text = Properties.Settings.Default.PortName;

            Control.CheckForIllegalCrossThreadCalls = false;


            try
            {
                FileNameStr = File.OpenRead(filename);
                long FileLen = FileNameStr.Length;
                textBox1.Text = (FileLen / 1024).ToString() + "K";
            }
            catch (Exception Err)
            {
                MessageBox.Show(Err.Message);
            }
            if (FileNameStr != null)
            {
                FileNameStr.Close();
            }
        }

        private void SendData()
        {
            FileNameStr = File.OpenRead(filename);
            long FileLen = FileNameStr.Length;
            byte[] CrcValue = new byte[300];
            long time = 50000;
            long RestLen;   //不足50K的长度
            
            //定义二维数组
            for (int i = 0; i < ((FileLen / ByteOne) + 1); i++)
            {
                FileReadByte[i] = new byte[ByteOne];
            }

            //
            //将文件存入到FileReadByte数组中，每一个维50K
            //
            int LenNum = (int)(FileLen / ByteOne);       //计算文件保存的次数
            for (int i = 0; i < LenNum; i++)
            {
                for (int j = 0; j < ByteOne; j++)
                {
                    FileReadByte[i][j] = (Byte)FileNameStr.ReadByte();
                }
                CrcValue[i] = CRC8(FileReadByte[i], 0, ByteOne);
            }

            //不足50K的部分
            if (FileLen > ByteOne)
            {
                RestLen = FileLen - (ByteOne * LenNum);
            }
            else
            {
                RestLen = FileLen;
            }

            for (int j = 0; j < RestLen; j++)
            {
                FileReadByte[LenNum][j] = (Byte)FileNameStr.ReadByte();
            }
            CrcValue[LenNum] = CRC8(FileReadByte[LenNum], 0, RestLen);
            FileNameStr.Close();    //关闭文档                           


            if (!serialPort1.IsOpen)
            {
                MessageBox.Show("请打开串口！");
                return;
            }

            //
            //接收到起始码
            //
            if (ReceivedOk == true)
            {
                ReceivedOk = false;

                Thread.Sleep(100);      //延时100ms发送bootloader文件
                //
                //发送bin文件
                //
                int sendcnt = 1024;
                int BufSize = 1024;
                progressbar.Maximum = (int)FileLen / BufSize + 1;
                progressbar.Value = 0;

                int j = 0;
                int m = 0;
                while (true)
                {
                    if (SendFlag == true)   //等待接收到下位准备
                    {
                        m = 0;
                        if (LenNum == 0)
                        {
                            break;
                        }
                        SendFlag = false;
                        for (int i = 0; i < (ByteOne / 1024); i++)
                        {
                            serialPort1.Write(FileReadByte[j], (int)i * BufSize, sendcnt);
                            progressbar.Value++;
                            textBox4.Text = progressbar.Value.ToString();
                            Thread.Sleep(10);
                        }
                        if (j < (LenNum - 1))
                        {
                            j++;
                        }
                        else
                        {
                            break;
                        }
                    }
                    Thread.Sleep(100);
                    m++;
                    if (m == time)
                    {
                        goto END;
                    }
                }

                //
                //CRC校验
                //
                //byte[] CrcValue = new byte[1];
                //CrcValue[0] = CRC8(FileReadByte[0], 0, (int)FileLen);
                //serialPort1.Write(CrcValue, 0, 1);
                m = 0;
                while (true)
                {
                    if (SendFlag == true)   //等待接收到下位准备
                    {
                        m = 0;
                        SendFlag = false;
                        for (int i = 0; i < RestLen / BufSize + 1; i++)
                        {
                            if (i == RestLen / BufSize) sendcnt = (int)RestLen % BufSize;
                            serialPort1.Write(FileReadByte[LenNum], (int)i * BufSize, sendcnt);
                            progressbar.Value++;
                            textBox4.Text = progressbar.Value.ToString();
                            Thread.Sleep(10);
                        }
                        break;
                    }
                    Thread.Sleep(100);
                    m++;
                    if (m == time)
                    {
                        goto END;
                    }
                }

                //通讯超时错误 m=50代表5秒钟            
                END:
                if (m == time)
                {
                    progressbar.Value = 0;
                    textBox5.AppendText("超时错误！" + "\r\n");
                }
            }
            if (serialPort1.IsOpen)
            {
                button3.Text = "开启";
                serialPort1.Close();
            }
        }

        /// <summary>
        /// 发送和设备连接的通信"start"持续发送5S一旦接收到"SETOK"则退出
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            if (!serialPort1.IsOpen)
            {
                button3.Text = "关闭";
                try
                {
                    serialPort1.PortName = comboBox1.Text;
                    serialPort1.BaudRate = Convert.ToInt32(comboBox2.Text);
                    serialPort1.Open();
                    serialPort1.Write("update\r\n");
                }
                catch
                {
                    MessageBox.Show("串口开启错误！");
                }
            }
            else
            {
                serialPort1.Write("update\r\n");
            }
        }

        /*串口端口扫描功能*/
        private void SearchAndAddSerialToComboBox(ComboBox Mybox)
        {
            Mybox.Items.Clear();
            String[] Portname = SerialPort.GetPortNames();
            foreach (string str in Portname)
            {
                Mybox.Items.Add(str);
            }
        }

        private void comboBox1_Click(object sender, EventArgs e)
        {
            SearchAndAddSerialToComboBox(comboBox1);            
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            Properties.Settings.Default.BaudRate = comboBox2.Text;
            Properties.Settings.Default.PortName = comboBox1.Text;
            Properties.Settings.Default.filename = filename;
            Properties.Settings.Default.Save();
        }


        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                string str = serialPort1.ReadTo("\r\n");
                textBox5.AppendText(str + "\r\n");
                //判断是否接收到SETOK，收到将标志置1
                if (str.Contains("SETOK"))
                {
                    ReceivedOk = true;
                    SendFlag = true;
                    t = new Thread(SendData);
                    t.Start();
                }

                //CRC校验错误
                if (str.Contains("crcerr"))
                {
                    textBox5.AppendText("CRC校验错误，请重新更新！" + "\r\n");
                }

                if (str.Contains("next"))
                {
                    SendFlag = true;
                }

                if (str.Contains("begin"))
                {                  
                    timerCount = 0;
                    ByteOne = Convert.ToInt32(str.Substring(str.IndexOf("begin") + 5, 6));
                    textBox3.Text = (ByteOne / 1024).ToString();
                    Thread t = new Thread(Send_Start_Com);
                    t.Start();
                }
                
            }
            catch
            {

            }
        }

        private void timer()
        {
            while (true)
            {
                timerCount++;
                label5.Text = timerCount.ToString();
                Thread.Sleep(100);
            }
        }

        //回复启动命令
        private void Send_Start_Com()
        {
            FileNameStr = File.OpenRead(filename);
            long FileLen = FileNameStr.Length;
            byte[] CrcValue = new byte[300];

            long RestLen;   //不足50K的长度

            //定义二维数组
            for (int i = 0; i < ((FileLen / ByteOne) + 1); i++)
            {
                FileReadByte[i] = new byte[ByteOne];
            }

            //
            //将文件存入到FileReadByte数组中，每一个维50K
            //
            int LenNum = (int)(FileLen / ByteOne);       //计算文件保存的次数
            for (int i = 0; i < LenNum; i++)
            {
                for (int j = 0; j < ByteOne; j++)
                {
                    FileReadByte[i][j] = (Byte)FileNameStr.ReadByte();
                }
                CrcValue[i] = CRC8(FileReadByte[i], 0, ByteOne);
            }

            //不足50K的部分
            if (FileLen > ByteOne)
            {
                RestLen = FileLen - (ByteOne * LenNum);
            }
            else
            {
                RestLen = FileLen;
            }

            for (int j = 0; j < RestLen; j++)
            {
                FileReadByte[LenNum][j] = (Byte)FileNameStr.ReadByte();
            }
            CrcValue[LenNum] = CRC8(FileReadByte[LenNum], 0, RestLen);
            FileNameStr.Close();    //关闭文档                           


            if (!serialPort1.IsOpen)
            {
                MessageBox.Show("请打开串口！");
                return;
            }
            //发送start起始码，接收到SETOK则进行更新程序
            serialPort1.Write("start");
            serialPort1.Write(FileLen.ToString("0000000") + "\r\n");         //发送文件长度标志LEN开头
            serialPort1.Write(CrcValue, 0, LenNum + 1);             //发送CRC
        }

        private void button3_Click(object sender, EventArgs e)
        {
            if (button3.Text == "开启")
            {
                button3.Text = "关闭";
                comboBox1.Enabled = false;
                try
                {
                    serialPort1.PortName = comboBox1.Text;
                    serialPort1.BaudRate = Convert.ToInt32(comboBox2.Text);
                    serialPort1.Open();
                }
                catch
                {
                    MessageBox.Show("串口开启错误！");
                }
            }
            else
            {
                comboBox1.Enabled = true;
                button3.Text = "开启";
                serialPort1.Close();
            }      
        }

        private byte CRC8(byte[] buffer, int startlength, long length)
        {
            byte crc = 0;
            for (long j = 0; j < length; j++)
            {
                crc ^= buffer[startlength + j];
                for (int i = 0; i < 8; i++)
                {
                    if ((crc & 0x01) != 0)
                    {
                        crc >>= 1;
                        crc ^= 0x8c;
                    }
                    else
                    {
                        crc >>= 1;
                    }
                }
            }
            return crc;
        }

        /// <summary>
        /// 单字节crc8计算
        /// </summary>
        /// <param name="data1">前一个CRC计算的数值</param>
        /// <param name="data2">后一个加入CRC计算的数</param>
        /// <returns></returns>
        private byte OneByteCRC8(byte data1, byte data2)
        {
            byte crc = data1;
            crc ^= data2;
            for (int i = 0; i < 8; i++)
            {
                if ((crc & 0x01) != 0)
                {
                    crc >>= 1;
                    crc ^= 0x8c;
                }
                else
                {
                    crc >>= 1;
                }
            }
            return crc;
        }

        private void button2_Click(object sender, EventArgs e)
        {
            FileNameStr.Close();
        }

        private void textBox5_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            textBox5.Clear();
        }
    }
}
